home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / lpd.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  25KB  |  1,015 lines

  1. /* Internet LPD Server
  2.  *   written by David Johnson (dave@cs.olemiss.edu)
  3.  *
  4.  * This code is in the public domain.
  5.  *
  6.  * Revision History:
  7.  *
  8.  * Revision 1.5  91/09/28  dave
  9.  * Separate filenames in lpq -l with commas
  10.  * Log permission rejections to the queue error log file
  11.  *
  12.  * Revision 1.4  91/09/26  dave (from Hans-Juergen Knobloch)
  13.  * Reset secure flag on startup so the security features may be enabled
  14.  *     and disabled without leaving net
  15.  * Changed definition of priority to char
  16.  * Changed definition of job size in send_queue() to a long
  17.  * Changed formatting of date in send_queue()
  18.  *
  19.  * Revision 1.3  91/09/19  dave
  20.  * Had to update is_job_specified() since additional letter sequence
  21.  *
  22.  * Revision 1.2  91/09/17  dave
  23.  * Job number reported to lpq included part which was not numeric
  24.  * Long hostname in send_queue() would overflow line buffer
  25.  * Date in send_queue() was not terminated properly
  26.  *
  27.  * Revision 1.1  91/09/14  dave
  28.  * Finished permission checking
  29.  *
  30.  * Revision 1.0  91/09/04  dave
  31.  * Initial Release
  32.  *
  33.  */
  34. #include <stdio.h>
  35. #include <fcntl.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38. #include <sys/stat.h>
  39. #ifdef    __TURBOC__
  40. #include <io.h>
  41. #include <dir.h>
  42. #endif
  43. #include "global.h"
  44. #include "mbuf.h"
  45. #include "proc.h"
  46. #include "iface.h"
  47. #include "usock.h"
  48. #include "socket.h"
  49. #include "domain.h"
  50. #include "dirutil.h"
  51. #include "commands.h"
  52. #include "files.h"
  53. #include "lp.h"
  54. #include "lpd.h"
  55.  
  56. /* in lpdunsp.c */
  57. extern void start_all_unspoolers __ARGS((int s, void *unused, void *p));
  58. extern void start_unspooler __ARGS((char *queue));
  59.  
  60. /* in lpdsubr.c */
  61. extern void free_queue_status __ARGS((void));
  62. extern int  get_job_list __ARGS((char *directory, struct job_entry **job_list));
  63. extern int  get_new_sequence_no __ARGS((struct LPDtrans *LPD));
  64. extern int  init_queue_status __ARGS((void));
  65. extern int  is_unspooler_active __ARGS((char *queue, char **job));
  66. extern int  kill_unspooler __ARGS((char *queue));
  67. extern void lpd_log __ARGS((struct LPDtrans *LPD, char *message, ...));
  68. extern char *read_printcap __ARGS((struct LPDtrans *LPD, char *queue));
  69. extern int  read_status __ARGS((char *queue, unsigned int *flags, unsigned int *next_seq, char **message));
  70.  
  71. /* local functions - public */
  72.        char *extract_parms __ARGS((char *local_parms, int extra));
  73.        int  is_job_specified __ARGS((char *cf_name));
  74.        int  is_lpd_active __ARGS((void));
  75.        int  lpd0 __ARGS((int argc, char *argv[], void *p));
  76.        int  lpdstart __ARGS((int argc, char *argv[], void *p));
  77.        int  trunc_strcat __ARGS((char *dest, char *source, int max_length));
  78.  
  79. /* local functions - private */
  80. static int  check_printer __ARGS((struct LPDtrans *LPD, char *printer_name));
  81. static void cleanup __ARGS((char *spool_dir, char *filespec));
  82. static int  enter_translation __ARGS((struct LPDxlat *xlat_table, char *filename,
  83.                       char *remotefile));
  84. static int  fixup_and_write_control_file __ARGS((struct LPDtrans *LPD, char *filename));
  85. static int  get_owner __ARGS((char *directory, char *cf_name, char **owner));
  86. static void lpd __ARGS((int s, void *unused, void *p));
  87. static int  receive_control_file __ARGS((struct LPDtrans *LPD,
  88.                      unsigned long filesize, int s));
  89. static int  receive_data_file __ARGS((char *filename,
  90.                       unsigned long filesize, int s));
  91. static int  receive_job __ARGS((struct LPDtrans *LPD));
  92. static int  remove_files __ARGS((char *directory, char *cf_name));
  93. static int  remove_job __ARGS((struct LPDtrans *LPD, char *local_parms));
  94. static int  send_queue __ARGS((struct LPDtrans *LPD, int type, char *local_parms));
  95. static int  validate_control_file __ARGS((struct LPDtrans *LPD, char *priority));
  96.  
  97.  
  98. static int Slpd = -1;    /* Prototype socket for service */
  99.  
  100. int secure = 0;        /* default to non-secure */
  101.  
  102.  
  103. /* Start up LPD service */
  104. int
  105. lpdstart(argc,argv,p)
  106. int argc;
  107. char *argv[];
  108. void *p;
  109. {
  110.     struct sockaddr_in lsocket;
  111.     struct sockaddr_in from_addr;
  112.     int c, s, from_len;
  113.  
  114.     if( Slpd != -1 ) {
  115.         /* Already running! */
  116.         return 0;
  117.     }
  118.     secure = 0;
  119.  
  120.     optind = 1;        /* reinit getopt() */
  121. loop:    while((c = getopt(argc,argv,"s")) != EOF){
  122.         switch( c ) {
  123.             case 's':       /* secure */
  124.                 secure = 1;
  125.                 break;
  126.         }
  127.     }
  128.  
  129.     psignal( Curproc, 0 );    /* Don't keep the parser waiting */
  130.     chname( Curproc, "LPD listener" );
  131.  
  132.     init_queue_status();
  133.  
  134.     /*
  135.      * Print any entries remaining
  136.      */
  137.     newproc( "LPDstartup", 2048, start_all_unspoolers, 0, NULL, NULL, 0 );
  138.  
  139.     /*
  140.      * Wait for incoming jobs
  141.      */
  142.     lsocket.sin_family = AF_INET;
  143.     lsocket.sin_addr.s_addr = INADDR_ANY;
  144.     if( optind < argc )
  145.         lsocket.sin_port = atoi( argv[optind]);
  146.     else
  147.         lsocket.sin_port = IPPORT_LPD;
  148.  
  149.     Slpd = socket( AF_INET, SOCK_STREAM, 0 );
  150.     bind( Slpd, (char *)&lsocket, sizeof(lsocket) );
  151.     listen( Slpd, 1 );
  152.     for( ;; ) {
  153.         if( (s = accept( Slpd, (char *)&from_addr, &from_len )) == -1 )
  154.             break;    /* Service is shutting down */
  155.  
  156.         if( availmem() < Memthresh ) {
  157.             RESPOND_ERR( s );
  158.             usprintf( s, "server low on memory\n" );
  159.             shutdown( s, 1 );
  160.         } else {
  161. #ifdef notdef
  162.             if( from_addr.sin_port > 1023 ) {
  163.                 /* not allowed */
  164.                 close_s( s );
  165.                 continue;
  166.             }
  167. #endif
  168.             /* Spawn a server */
  169.             newproc( "LPDserv", 4096, lpd, s, NULL, NULL, 0 );
  170.         }
  171.     }
  172.     return 0;
  173. }
  174.  
  175. static void
  176. lpd(s,unused,p)
  177. int s;    /* Socket with user connection */
  178. void *unused;
  179. void *p;
  180. {
  181.     struct LPDtrans LPD;
  182.     char buf[512], printer[64], *remote_host, *sp, *dp;
  183.     int cnt = MAXSOCKSIZE;
  184.     union sp sockp;
  185.     char sc[MAXSOCKSIZE];
  186.     struct sockaddr_in from_addr;
  187.  
  188.     memset( (char *)&LPD, 0, sizeof(LPD) );    /* Start with clear slate */
  189.  
  190.     sockowner( s, Curproc );        /* We own it now */
  191.     sockmode( s, SOCK_BINARY );
  192.     LPD.remote = s;
  193.  
  194.     log( s,"open LPD" );
  195.     remote_host = NULL;
  196.     /*
  197.      * Obtain the "domain name" of the remote host to check permissions
  198.      */
  199.     getpeername( s, sc, &cnt );
  200.     sockp.p = sc;
  201. #ifdef LPD_DEBUG
  202.     tprintf( "secure %d from %s\n", secure, psocket(sc) );
  203. #endif
  204.     remote_host = resolve_a( sockp.in->sin_addr.s_addr, 0 );
  205.     if( *(remote_host + strlen(remote_host) - 1) == '.' )
  206.         *(remote_host + strlen(remote_host) - 1) = NULL;
  207. #ifdef LPD_DEBUG
  208.     tprintf( "remote host = %s\n", remote_host );
  209.     tflush();
  210. #endif
  211.  
  212. loop:    if( (cnt = recvline( s, buf, sizeof(buf) )) == -1){
  213.         /* He closed on us */
  214.         goto finish;
  215.     }
  216.     if( cnt == 0 ){
  217.         /* Can't be a legal LPD command */
  218.         RESPOND_ERR( LPD.remote );
  219.         goto loop;
  220.     }
  221.     rip( buf );
  222.     for( sp = buf+1, dp = printer; *sp && *sp != ' '; *dp++ = *sp++ )
  223.         ;
  224.     *dp = NULL;
  225. #ifdef LPD_DEBUG
  226.     tprintf( "LPD: request %d - %s\n", *buf, buf+1 );
  227. #endif
  228.     if( START_CMD <= *buf && *buf <= REMOVE_CMD ) {
  229.         LPD.pc = NULL;
  230.         if( (LPD.name = read_printcap( &LPD, printer )) == NULL ) {
  231.             RESPOND_ERR( LPD.remote );
  232.             usprintf( LPD.remote, "Printer %s (%s) not found.\n", printer, Hostname );
  233.             goto finish;
  234.         }
  235.     }
  236.     if( secure && !check_permission( remote_host, NULL, LPD.name, NULL ) ) {
  237.         RESPOND_ERR( LPD.remote );
  238.         usprintf( LPD.remote, "Your host is not authorized to use %s.\n", buf+1 );
  239.         /*
  240.          * Setup log file
  241.          */
  242.         LPD.logfp = fopen( LPD.pc->LF, "a" );
  243.         lpd_log( &LPD, "lpd: permission rejected for %s, %s, %s, %c ", remote_host, NULL, LPD.name, NULL );
  244.         if( LPD.logfp )
  245.             fclose( LPD.logfp );
  246.         goto finish;
  247.     }
  248.     switch( *buf ) {
  249.         case START_CMD:            /* Check queue and print */
  250.             /*
  251.              * Line format: \1printer\n
  252.              */
  253.             RESPOND_OK( LPD.remote );
  254.             close_s( s );            /* close connection */
  255.             start_unspooler( LPD.name );
  256.             break;
  257.         case RECEIVE_CMD:        /* Submit a print job */
  258.             /*
  259.              * Line format: \2printer\n
  260.              */
  261.             receive_job( &LPD );
  262.             break;
  263.         case SQUEUE_CMD:        /* Display Queue (short form) */
  264.             /*
  265.              * Line format: \3printer [users ...] [jobs ...]\n
  266.              */
  267.             send_queue( &LPD, SQUEUE_CMD, buf+1 );
  268.             break;
  269.         case QUEUE_CMD:            /* Display Queue (long form) */
  270.             /*
  271.              * Line format: \4printer [users ...] [jobs ...]\n
  272.              */
  273.             send_queue( &LPD, QUEUE_CMD, buf+1 );
  274.             break;
  275.         case REMOVE_CMD:        /* Remove a job from Queue */
  276.             /*
  277.              * Line format: \5printer person [users ...] [job ...]\n
  278.              */
  279.             remove_job( &LPD, buf+1 );
  280.             break;
  281.         default:            /* Invalid command */
  282.             RESPOND_ERR( LPD.remote );
  283.             usprintf( LPD.remote, "Invalid command\n" );
  284.     }
  285. finish:
  286.     log( LPD.remote,"close LPD" );
  287.  
  288.     /* Clean up */
  289.     close_s( LPD.remote );
  290.     if( LPD.pc )
  291.         free( LPD.pc );
  292.     if( LPD.name )
  293.         free( LPD.name );
  294.     if( remote_host )
  295.         free( remote_host );
  296. }
  297.  
  298. /* Shut down LPD server */
  299. int
  300. lpd0(argc,argv,p)
  301. int argc;
  302. char *argv[];
  303. void *p;
  304. {
  305.     close_s(Slpd);
  306.     Slpd = -1;
  307.     free_queue_status();
  308.  
  309.     return 0;
  310. }
  311.  
  312. static int
  313. receive_job( LPD )
  314. struct LPDtrans *LPD;
  315. {
  316.     char *strdup(), priority;
  317.     int cnt, sequence;
  318.     unsigned long filesize;
  319.     char buffer[512], newfilename[13], *path, *remotefile, *strchr();
  320.     FILE *fp;
  321.  
  322.     sequence = get_new_sequence_no( LPD );
  323.     sprintf( newfilename, "xfAA%03d", sequence );
  324.  
  325.     LPD->xlat_table = (struct LPDxlat *)callocw( 1, sizeof( struct LPDxlat ) );
  326.  
  327. #ifdef LPD_DEBUG
  328.     tprintf( "receive_job( %s )\n", newfilename );
  329.     tflush();
  330. #endif
  331.  
  332.     RESPOND_OK( LPD->remote );
  333.  
  334.     for( ;; ) {
  335.         if( (cnt = recvline( LPD->remote, buffer, sizeof(buffer) )) == -1 ){
  336.             /* He closed on us */
  337.             break;
  338.         }
  339.         if( cnt == 0 ){
  340.             /* Can't be a legal LPD command */
  341.             RESPOND_ERR( LPD->remote );
  342.             continue;
  343.         }
  344.         rip(buffer);
  345. #ifdef LPD_DEBUG
  346.         tprintf( "subcommand %d+%s\n", *buffer, buffer+1 );
  347.         tflush();
  348. #endif
  349.         switch( *buffer ) {
  350.             case ABORT_SCMD:    /* flush current files */
  351.                 cleanup( LPD->pc->SD, newfilename );
  352.                 break;
  353.             case RECEIVE_CF_SCMD:    /* control file */
  354.                 filesize = atol( buffer+1 );
  355.  
  356.                 if( receive_control_file( LPD, filesize, LPD->remote ) < 0 ) {
  357.                     tprintf( "could not receive control file\n" );
  358.                     cleanup( LPD->pc->SD, newfilename );
  359.                     return -1;
  360.                 }
  361.                 if( validate_control_file( LPD, &priority ) < 0 ) {
  362.                     RESPOND_ERR( LPD->remote );
  363.                     cleanup( LPD->pc->SD, newfilename );
  364.                     return -1;
  365.                 } else {
  366.                     RESPOND_OK( LPD->remote );
  367.                 }
  368.                 /*
  369.                  * Write out control file
  370.                  */
  371.                 newfilename[0] = 'c';        /* control file */
  372.                 newfilename[2] = priority;
  373.                 newfilename[3] = 'A';
  374.                 path = pathname( LPD->pc->SD, newfilename );
  375.                 fixup_and_write_control_file( LPD, path );
  376.                 free( path );
  377.                 break;
  378.             case RECEIVE_DF_SCMD:
  379.                 filesize = atol( buffer+1 );
  380.                 newfilename[0] = 'd';    /* data file */
  381.                 path = pathname( LPD->pc->SD, newfilename );
  382.  
  383.                 remotefile = strchr( buffer+1, ' ' ) + 1;
  384.  
  385.                 if( receive_data_file( path, filesize, LPD->remote ) < 0 ) {
  386.                     tprintf( "could not receive %s(%s)\n", remotefile, path );
  387.                     cleanup( LPD->pc->SD, newfilename );
  388.                     free( path );
  389.                     return -1;
  390.                 }
  391.                 free( path );
  392.                 enter_translation( LPD->xlat_table, newfilename, remotefile );
  393.  
  394.                 /* increment file letters */
  395.                 newfilename[3] = newfilename[3] + 1;
  396.                 if( newfilename[3] > 'Z' ) {
  397.                     newfilename[3] = 'A';
  398.                     newfilename[2] = newfilename[2] + 1;
  399.                 }
  400.  
  401.                 RESPOND_OK( LPD->remote );
  402.                 break;
  403.         }
  404.     }
  405.     free( LPD->xlat_table );
  406.     chname( Curproc, "LPDprint" );
  407.     start_unspooler( strdup( LPD->name ) );
  408. }
  409.  
  410. static int
  411. check_printer( LPD, printer_name )
  412. struct LPDtrans *LPD;
  413. char *printer_name;
  414. {
  415.     char *p1, *p2;
  416.  
  417.     p1 = printer_name;
  418.     p2 = LPD->name;
  419.  
  420.     while( *p1 && *p1 != ' ' )
  421.         *p2++ = *p1++;
  422.     p2 = NULL;
  423. }
  424.  
  425. /*
  426.  * cleanup - remove current control and data files
  427.  */
  428. static void
  429. cleanup( spool_dir, filespec )
  430. char *spool_dir, *filespec;
  431. {
  432.     char *path;
  433.  
  434.     /* remove all data files */
  435.     filespec[0] = 'd';
  436.         do {
  437.             do {
  438.                 path = pathname( spool_dir, filespec );
  439.                 remove( path );
  440.                 free( path );
  441.             } while( filespec[3]-- != 'A' );
  442.         filespec[3] = 'Z';
  443.  
  444.         } while( filespec[2]-- != 'A' );
  445.  
  446.     /* remove control file */
  447.     filespec[0] = 'c';
  448.     filespec[2] = 'A';
  449.     filespec[3] = 'A';
  450.     path = pathname( spool_dir, filespec );
  451.     remove( path );
  452.     free( path );
  453. }
  454.  
  455. static int
  456. receive_data_file( filename, filesize, s )
  457. char *filename;
  458. unsigned long filesize;
  459. int s;
  460. {
  461.     int bytes, blocksize;
  462.     unsigned long total = 0;
  463.     char *buffer, status;
  464.     FILE *fp;
  465.  
  466. #ifdef LPD_DEBUG
  467.     tprintf( "receive_data_file( %ld )\n", filesize );
  468.     tflush();
  469. #endif
  470.  
  471.     fp = fopen( filename, WRITE_BINARY );
  472.  
  473.     filesize++;    /* add in status byte */
  474.     blocksize = filesize > BLOCKSIZE ? BLOCKSIZE : filesize;
  475.     buffer = (char *)malloc( blocksize );
  476.  
  477.     RESPOND_OK( s );
  478.     do {
  479.         if( (bytes = recv( s, buffer, blocksize, 0 )) < 1 ) {
  480.             free( buffer );
  481.             fclose( fp );
  482.             return -1;
  483.         }
  484.         if( total + bytes == filesize ) {
  485.             bytes--;    /* don't save status byte */
  486.             status = *(buffer + bytes);
  487.             total++;
  488.         }
  489.         if( fwrite( buffer, bytes, 1, fp ) == 0 ) {
  490.             free( buffer );
  491.             fclose( fp );
  492.             return -1;
  493.         }
  494.         total += bytes;
  495.         if( filesize - total < BLOCKSIZE )/* handle last portion */
  496.             blocksize = filesize - total;
  497.     } while( total < filesize );
  498.     free( buffer );
  499.     fclose( fp );
  500.  
  501.     if( status != STATUS_OK ) {
  502.         tprintf( "bad status\n" );
  503.         tflush();
  504.         return -1;
  505.     }
  506.     return 0;
  507. }
  508.  
  509. static int
  510. receive_control_file( LPD, filesize, s )
  511. struct LPDtrans *LPD;
  512. unsigned long filesize;
  513. int s;
  514. {
  515.     int c, bytes, blocksize;
  516.     unsigned long total = 0;
  517.     char *buffer, status;
  518.  
  519. #ifdef LPD_DEBUG
  520.     tprintf( "receive_control_file( %ld )\n", filesize );
  521.     tflush();
  522. #endif
  523.  
  524.     LPD->cf_data = (char *)mallocw( filesize+1 );    /* + NULL byte */
  525.     buffer = LPD->cf_data;
  526.  
  527.     filesize++;    /* add in status byte */
  528.     blocksize = filesize > BLOCKSIZE ? BLOCKSIZE : filesize;
  529.  
  530.     RESPOND_OK( s );
  531.     do {
  532.         if( (bytes = recv( s, buffer, blocksize, 0 )) < 1 ) {
  533.             free( LPD->cf_data );
  534.             return -1;
  535.         }
  536.         if( total + bytes == filesize ) {
  537.             bytes--;    /* don't save status byte */
  538.             status = *(buffer + bytes);
  539.             total++;
  540.         }
  541.         buffer += bytes;
  542.         total += bytes;
  543.         if( filesize - total < BLOCKSIZE )/* handle last portion */
  544.             blocksize = filesize - total;
  545.     } while( total < filesize );
  546.     LPD->cf_data[ filesize-1 ] = NULL;        /* add NULL byte */
  547.  
  548.     if( status != STATUS_OK ) {
  549.         tprintf( "bad status\n" );
  550.         tflush();
  551.         return -1;
  552.     }
  553.     return 0;
  554. }
  555.  
  556. static int
  557. enter_translation( xlat_table, filename, remotefile )
  558. struct LPDxlat *xlat_table;
  559. char *filename, *remotefile;
  560. {
  561.     char *strdup();
  562.     int index;
  563.  
  564. #ifdef LPD_DEBUG
  565.     tprintf( "enter_translation( %s, %s )\n", filename, remotefile );
  566.     tflush();
  567. #endif
  568.  
  569.     for( index = 0; index < 32; index++ ) {
  570.         if( xlat_table->xlat[ index ].dfname == NULL ) {
  571.             /* found an empty slot */
  572.             xlat_table->xlat[ index ].dfname = strdup( remotefile );
  573.             xlat_table->xlat[ index ].dos_dfname = strdup( filename );
  574.             return;
  575.         }
  576.     }
  577.     YIELD;
  578. }
  579.  
  580. static int
  581. fixup_and_write_control_file( LPD, filename )
  582. struct LPDtrans *LPD;
  583. char *filename;
  584. {
  585.     char *ptr, *strchr(), old_filename[128], *optr;
  586.     int index;
  587.     FILE *fp;
  588.  
  589. #ifdef LPD_DEBUG
  590.     tprintf( "fixup_and_write_control_file( %s )\n", filename );
  591.     tflush();
  592. #endif
  593.  
  594.     fp = fopen( filename, WRITE_TEXT );
  595.  
  596.     ptr = LPD->cf_data;
  597.     while( *ptr ) {
  598.         if( *ptr > 'a' && *ptr <'z' || *ptr == 'U' ) {
  599.             /* translation needed */
  600.  
  601.             putc( *ptr++, fp );
  602.             optr = old_filename;
  603.             while( *ptr && *ptr != '\n' )
  604.                 *optr++ = *ptr++;
  605.             *optr = NULL;
  606.             for( index = 0; index < 32; index++ ) {
  607.                 if( strcmp( LPD->xlat_table->xlat[ index ].dfname, old_filename ) == 0 ) {
  608.                     /* found the translation */
  609.                     fputs( LPD->xlat_table->xlat[ index ].dos_dfname, fp );
  610.                     break;
  611.                 }
  612.             }
  613.         }
  614.         while( *ptr && *ptr != '\n' )
  615.             putc( *ptr++, fp );
  616.         if( *ptr == NULL )
  617.             break;
  618.         putc( *ptr++, fp );            /* output linefeed */
  619.         YIELD;
  620.     }
  621.     fclose( fp );
  622.     free( LPD->cf_data );
  623.  
  624.     /*
  625.      * Clean up translations
  626.      */
  627.     for( index = 0; index < 32; index++ ) {
  628.         if( LPD->xlat_table->xlat[ index ].dfname != NULL ) {
  629.             /* clean slot */
  630.             free( LPD->xlat_table->xlat[ index ].dfname );
  631.             free( LPD->xlat_table->xlat[ index ].dos_dfname );
  632.             LPD->xlat_table->xlat[ index ].dfname = NULL;
  633.         }
  634.     }
  635.     YIELD;
  636.     return 0;
  637. }
  638.  
  639. static int
  640. validate_control_file( LPD, priority )
  641. struct LPDtrans *LPD;
  642. char *priority;
  643. {
  644.     char *ptr, host[64], user[32], class[32];
  645.     int index;
  646.  
  647. #ifdef LPD_DEBUG
  648.     tprintf( "validating control file\n" );
  649.     tflush();
  650. #endif
  651.  
  652.     memset( host, 0, sizeof( host ) );
  653.     memset( user, 0, sizeof( user ) );
  654.     memset( class, 0, sizeof( class ) );
  655.  
  656.     /*
  657.      * Extract info to test permissions
  658.      */
  659.     ptr = LPD->cf_data;
  660.     while( *ptr ) {
  661.         if( *ptr == 'H' ) {        /* host name */
  662.             index = 0;
  663.             while( *++ptr && *ptr != '\n' )
  664.                 host[index++] = *ptr;
  665.             host[index] = NULL;
  666.         } else if( *ptr == 'P' ) {    /* login name */
  667.             index = 0;
  668.             while( *++ptr && *ptr != '\n' )
  669.                 user[index++] = *ptr;
  670.             user[index] = NULL;
  671.         } else if( *ptr == 'C' ) {    /* class or priority */
  672.             index = 0;
  673.             while( *++ptr && *ptr != '\n' )
  674.                 class[index++] = *ptr;
  675.             class[index] = NULL;
  676.         }
  677.         while( *ptr && *ptr != '\n' )
  678.             ptr++;
  679.         if( *ptr++ == NULL )
  680.             break;
  681.         YIELD;
  682.     }
  683.     *priority = *class;
  684.     if( priority == 0 )
  685.         *priority = 'Z';
  686.     if( !isascii( *priority ) || !isupper( *priority ) )
  687.         *priority = 'Z';
  688.  
  689.     YIELD;
  690.     if( secure && !check_permission( host, user, LPD->name, priority ) ) {
  691.         /*
  692.          * Setup log file
  693.          */
  694.         LPD->logfp = fopen( LPD->pc->LF, "a" );
  695.         lpd_log( LPD, "lpd: permission rejected for %s, %s, %s, %c ", host, user, LPD->name, *priority );
  696.         if( LPD->logfp )
  697.             fclose( LPD->logfp );
  698.         return -1;
  699.     }
  700.     YIELD;
  701.     return 0;
  702. }
  703.  
  704. int
  705. is_lpd_active(void)
  706. {
  707.     return( (Slpd == -1) ? 0 : 1 );
  708. }
  709.  
  710. static char *parms[ MAX_PARMS ];
  711. static int  parms_count;
  712.  
  713. char *
  714. extract_parms( local_parms, extra )
  715. char *local_parms;
  716. int extra;
  717. {
  718.     char *cp, *skipp;
  719.  
  720.     cp = strtok( local_parms, " " );    /* skip <printer> */
  721.     while( --extra > 0 )
  722.         skipp = strtok( NULL, " " );    /* skip other unused parms */
  723.  
  724.     /*
  725.      * Build parameter list
  726.      */
  727.     parms_count = 0;
  728.     while( parms_count < MAX_PARMS && (cp = strtok( NULL, " " )) != NULL )
  729.         parms[ parms_count++ ] = cp;
  730.  
  731.     return( skipp );            /* last skipped parameter */
  732. }
  733.  
  734. int
  735. send_queue( LPD, type, local_parms )
  736. struct LPDtrans *LPD;
  737. int type;
  738. char *local_parms;
  739. {
  740.     int active;
  741.     unsigned int flags, next_seq, job_count, job;
  742.     char *message, status[32], line[81];
  743.     char *path, *active_job, *strdup();
  744.     struct job_entry *job_list;
  745.     struct stat fstatus;
  746.     FILE *cfp;
  747.  
  748.     /* job specific info */
  749.     char *owner, host[12], files[21], date[12], *suffix;
  750.     long size;
  751.  
  752. #ifdef LPD_DEBUG
  753.     tprintf( "send_queue( %s, %d )\n", LPD->name, type );
  754.     tflush();
  755. #endif
  756.  
  757.     (void)extract_parms( local_parms, 1 );
  758.  
  759.     active = is_unspooler_active( LPD->name, &active_job );
  760.     job_count = get_job_list( LPD->pc->SD, &job_list );
  761.  
  762.     read_status( LPD->name, &flags, &next_seq, &message );
  763.     *status = NULL;
  764.     if( (flags & QUEUE_ENABLED) == 0 )
  765.         strcat( status, "no spooling" );
  766.     if( (flags & PRINT_ENABLED) == 0 ) {
  767.         if( *status )
  768.             strcat( status, ", " );
  769.         strcat( status, "no printing" );
  770.     }
  771.  
  772.     if( type == SQUEUE_CMD ) {
  773.         usprintf( LPD->remote, "%s: %d jobs", LPD->name, job_count );
  774.         if( *status )
  775.             usprintf( LPD->remote, " (%s)", status );
  776.         usputc( LPD->remote, '\n' );
  777.     } else {
  778.         usprintf( LPD->remote, "Printer '%s' (%s)", LPD->name, Hostname );
  779.         if( LPD->pc->CM )
  780.             usprintf( LPD->remote, " %s", LPD->pc->CM );
  781.         usputc( LPD->remote, ':' );
  782.         if( *status )
  783.             usprintf( LPD->remote, " (%s)", status );
  784.         usputc( LPD->remote, '\n' );
  785.         if( job_count > 0 && !active )
  786.             usputs( LPD->remote, "Warning: no unspooler present\n" );
  787.         usprintf( LPD->remote, "  %s\n", message );
  788.     }
  789.  
  790.     if( job_count > 0 && type == QUEUE_CMD ) {
  791.         usputs( LPD->remote, "  Rank Owner       Pr Job Host        Files" );
  792.         usputs( LPD->remote, "                Size   Date\n" );
  793.     }
  794.  
  795.     /*
  796.      * Read each control file for information and display
  797.      */
  798.     for( job = 0; job < job_count; job++ ) {
  799.  
  800.         if( !is_job_specified( job_list[ job ].j_name ) ) {
  801.             free( job_list[ job ].j_name );
  802.             continue;
  803.         }
  804.  
  805.         size = 0;
  806.         *host = NULL;
  807.         *files = NULL;
  808.  
  809.         path = pathname( LPD->pc->SD, job_list[ job ].j_name );
  810.  
  811.         if( (cfp = fopen( path, "r" )) == NULL ) {
  812.             free( path );
  813.             continue;
  814.         }
  815.         stat( path, &fstatus );
  816.         free( path );
  817.  
  818.         sprintf( date, "%7.7s%4.4s", ctime( &fstatus.st_mtime ) +  4,
  819.                          ctime( &fstatus.st_mtime ) + 20 );
  820.  
  821.         while( fgets( line, 80, cfp ) != NULL ) {
  822.             rip( line );
  823.             if( islower( *line ) ) {
  824.                 path = pathname( LPD->pc->SD, line+1 );
  825.                 if( stat( path, &fstatus ) != 0 ) {
  826.                     free( path );
  827.                     continue;
  828.                 }
  829.                 free( path );
  830.                 size += fstatus.st_size;
  831.             } else if( *line == 'P' ) {
  832.                 owner = strdup( line+1 );
  833.             } else if( *line == 'N' ) {
  834.                 if( *files )
  835.                     trunc_strcat( files, ",", 20 );
  836.                 trunc_strcat( files, line+1, 20 );
  837.             } else if( *line == 'H' ) {
  838.                 trunc_strcat( host, line+1, 11 );
  839.             }
  840.         }
  841.         fclose( cfp );
  842.         if( type == SQUEUE_CMD ) {        /* short form */
  843.             usprintf( LPD->remote, "%d cf%s: %s\n", job+1, job_list[ job ].j_name+2, owner );
  844.         } else {                /* long form */
  845.             if( strcmp( active_job, job_list[ job ].j_name ) == 0 ) {
  846.                 strcpy( line, "active" );
  847.             } else {
  848.                 switch( job+1 ) {
  849.                     case 1:  suffix = "st"; break;
  850.                     case 2:  suffix = "nd"; break;
  851.                     case 3:  suffix = "rd"; break;
  852.                     default: suffix = "th"; break;
  853.                 }
  854.                 sprintf( line, "%d%s", job+1, suffix );
  855.             }
  856.  
  857.             usprintf( LPD->remote, "%6s %-11s %-c  %-3s %-11s %-20s %-6ld %s\n",
  858.                     line,                /* rank */
  859.                     owner,                /* owner */
  860.                     job_list[ job ].j_name[2],  /* priority */
  861.                     job_list[ job ].j_name + 4, /* job */
  862.                     host,                /* host */
  863.                     files,                /* files in job */
  864.                     size,                /* job size */
  865.                     date                /* date submitted */
  866.                 );
  867.         }
  868.         free( job_list[ job ].j_name );
  869.  
  870.         free( owner );
  871.     }
  872.     if( job_count > 0 )
  873.         free( job_list );
  874. }
  875.  
  876. int
  877. trunc_strcat( dest, source, max_length )
  878. char *dest, *source;
  879. int max_length;
  880. {
  881.     strncat( dest, source, max_length - strlen( dest ) );
  882. }
  883.  
  884. int
  885. is_job_specified( cf_name )
  886. char *cf_name;
  887. {
  888.     int parm, job_spec, job_no;
  889.  
  890.     if( parms_count == 0 )        /* match all */
  891.         return 1;
  892.     for( parm = 0; parm < parms_count; parm++ ) {
  893.         if( isdigit( *parms[ parm ] ) ) {    /* job number specified */
  894.  
  895.             job_spec = atoi( parms[ parm ] );
  896.             job_no = atoi( cf_name + 4 );
  897.  
  898.             if( job_spec == job_no )
  899.                 return 1;
  900.         }                /* user name - NOT SUPPORTED */
  901.     }
  902.     return 0;
  903. }
  904.  
  905. static int
  906. get_owner( directory, cf_name, owner )
  907. char *directory, *cf_name, **owner;
  908. {
  909.     char *path, line[81];
  910.     FILE *cfp;
  911.  
  912.     *owner = NULL;
  913.  
  914.     path = pathname( directory, cf_name );
  915.     if( (cfp = fopen( path, "r" )) == NULL ) {
  916.         free( path );
  917.         return -1;
  918.     }
  919.     free( path );
  920.  
  921.     while( fgets( line, 80, cfp ) != NULL ) {
  922.         rip( line );
  923.         if( *line == 'P' )
  924.             *owner = strdup( line+1 );
  925.     }
  926.     fclose( cfp );
  927.  
  928.     return 0;
  929. }
  930.  
  931. static int
  932. remove_files( directory, cf_name )
  933. char *directory, *cf_name;
  934. {
  935.     char *path, line[81];
  936.     FILE *cfp;
  937.  
  938.     path = pathname( directory, cf_name );
  939.     if( (cfp = fopen( path, "r" )) == NULL ) {
  940.         free( path );
  941.         return -1;
  942.     }
  943.     free( path );
  944.  
  945.     while( fgets( line, 80, cfp ) != NULL ) {
  946.         rip( line );
  947.         if( *line == 'U' ) {
  948.             path = pathname( directory, line+1 );
  949.             remove( path );
  950.             free( path );
  951.         }
  952.     }
  953.     fclose( cfp );
  954.  
  955.     path = pathname( directory, cf_name );
  956.     remove( path );
  957.     free( path );
  958.  
  959.     return 0;
  960. }
  961.  
  962. static int
  963. remove_job( LPD, local_parms )
  964. struct LPDtrans *LPD;
  965. char *local_parms;        /* <printer> <user> <jobs> */
  966. {
  967.     int all, active, job, job_count;
  968.     char *user, *owner, *cp;
  969.     char *active_job;
  970.     struct job_entry *job_list;
  971.  
  972.     usprintf( LPD->remote, "Printer '%s' (%s):\n", LPD->name, Hostname );
  973.  
  974.     user = extract_parms( local_parms, 2 );
  975.  
  976.     active = is_unspooler_active( LPD->name, &active_job );
  977.     job_count = get_job_list( LPD->pc->SD, &job_list );
  978.  
  979.     /*
  980.      * Check each job against request
  981.      */
  982.     for( job = 0; job < job_count; job++ ) {
  983.  
  984.         if( get_owner( LPD->pc->SD, job_list[ job ].j_name, &owner ) < 0 )
  985.             continue;
  986.         if( strcmp( user, owner ) != 0 ) {    /* not owner of job */
  987.             free( owner );
  988.             continue;
  989.         }
  990.  
  991.         if( is_job_specified( job_list[ job ].j_name ) ) {
  992.             usprintf( LPD->remote, "removing cf%s, job %-3s owner %s\n", 
  993.                     job_list[ job ].j_name + 2,
  994.                     job_list[ job ].j_name + 3,
  995.                     owner );
  996.  
  997.             if( active && strcmp( job_list[ job ].j_name, active_job ) == 0 ) {
  998.                 /* unspooler is processing our job, kill it */
  999.  
  1000.                 usprintf( LPD->remote, "killing off %s unspooler\n", LPD->name );
  1001.  
  1002.                 kill_unspooler( LPD->name );
  1003.             }
  1004.             remove_files( LPD->pc->SD, job_list[ job ].j_name );
  1005.             YIELD;
  1006.         }
  1007.         free( job_list[ job ].j_name );
  1008.         free( owner );
  1009.     }
  1010.     free( job_list );
  1011.  
  1012.     YIELD;
  1013.     return 0;
  1014. }
  1015.